package org.apache.rocketmq.client.impl.factory;


import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.impl.MQClientAPIImpl;
import org.apache.rocketmq.common.ServiceState;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.netty.NettyClientConfig;

/*
 *@方法描述：控制台客户端实例，这里我想跟大家解释一下，这个客户端对象以及其实现类MQClientAPIImpl客户端并不是只在控制台模块中使用
 * 实际上在Proxy模块中也会使用到，这里的客户端实例实际上就是RocketMQ客户端的核心组件之一，负责客户端与服务器的网络通信
 * 如果我们使用的是5.0之前的MQ框架，那么大家就会发现生产者消费者的客户端使用的就是这个客户端实例，并且在MQ内部各个组件通信的时候，也会用到这个客户端实例
 * 而在5.0版本之后，生产者消费者开始使用grpc客户端了，这个客户端实例就主要用于内部各个模块的通信了
 * 我在第六版本代码中为大家展示的客户端都是最简化的客户端，随着代码版本的迭代，这些类的内容也会逐渐完善
 */
public class MQClientInstance {
    private final static Logger log = LoggerFactory.getLogger(org.apache.rocketmq.client.impl.factory.MQClientInstance.class);

    //客户端配置
    private final ClientConfig clientConfig;

    //客户端ID
    private final String clientId;

    //Netty客户端配置
    private final NettyClientConfig nettyClientConfig;

    //MQClientAPI实例
    private final MQClientAPIImpl mQClientAPIImpl;

    //当前客户端实例状态
    private ServiceState serviceState = ServiceState.CREATE_JUST;

    public MQClientInstance(ClientConfig clientConfig, int instanceIndex, String clientId) {
        this(clientConfig, instanceIndex, clientId, null);
    }

    //构造方法
    public MQClientInstance(ClientConfig clientConfig, int instanceIndex, String clientId, RPCHook rpcHook) {
        this.clientConfig = clientConfig;
        this.nettyClientConfig = new NettyClientConfig();
        this.nettyClientConfig.setClientCallbackExecutorThreads(clientConfig.getClientCallbackExecutorThreads());
        this.nettyClientConfig.setUseTLS(clientConfig.isUseTLS());
        this.nettyClientConfig.setSocksProxyConfig(clientConfig.getSocksProxyConfig());
        //创建控制台客户端的api对象，该对象负责客户端与服务器的网络通信
        this.mQClientAPIImpl = new MQClientAPIImpl(this.nettyClientConfig, null, rpcHook, clientConfig, null);
        //把Namesrv的地址设置到客户端的配置信息中
        if (this.clientConfig.getNamesrvAddr() != null) {
            //更新客户端中缓存的Namesrv地址列表
            this.mQClientAPIImpl.updateNameServerAddressList(this.clientConfig.getNamesrvAddr());
            log.info("user specified name server address: {}", this.clientConfig.getNamesrvAddr());
        }
        //设置客户端ID
        this.clientId = clientId;
    }

    public void start() {
        synchronized (this) {
            switch (this.serviceState) {
                case CREATE_JUST:
                    this.serviceState = ServiceState.START_FAILED;
                    //启动MQClientAPI实例
                    this.mQClientAPIImpl.start();
                    log.info("the mqClient instance[{}] start OK", this.clientId);
                    this.serviceState = ServiceState.RUNNING;
                    break;
                case START_FAILED:
                    throw new RuntimeException("the mqClient instance[" + this.clientId + "] START FAILED");
                default:
                    break;
            }
        }
    }

    public void shutdown() {
        synchronized (this) {
            switch (this.serviceState) {
                case RUNNING:
                    this.serviceState = ServiceState.SHUTDOWN_ALREADY;
                    this.mQClientAPIImpl.shutdown();
                    MQClientManager.getInstance().removeClientFactory(this.clientId);
                    log.info("the client factory [{}] shutdown OK", this.clientId);
                    break;
                case CREATE_JUST:
                case SHUTDOWN_ALREADY:
                default:
                    break;
            }
        }
    }

    public String getClientId() {
        return clientId;
    }

    public MQClientAPIImpl getMQClientAPIImpl() {
        return mQClientAPIImpl;
    }
}